package api

import (
	"chat/global"
	"chat/internal/models/dao"
	"chat/internal/models/services"
	"chat/internal/request"
	"chat/pkg"
	"encoding/json"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"log"
	"math/rand"
	"net/http"
	"path/filepath"
	"time"
)

func MobileRegister(c *gin.Context) {
	var req request.MobileRegisterReq
	err := c.ShouldBind(&req)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "数据不能为空",
		})
		return
	}
	user := dao.User{
		Mobile: req.Mobile,
	}
	err = services.CreateUser(user)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "注册失败",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "注册成功",
		})
	}
}

func SendSms(c *gin.Context) {
	var req request.SendSmsReq
	err := c.ShouldBind(&req)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "数据不能为空",
		})
		return
	}
	code := rand.Intn(9999) + 1000
	err = global.RedisClient.Set(services.GetSmsKey(req.Mobile), code, time.Minute*30).Err()
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "短信发送失败",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "短信发送成功",
		})
	}
}

func Login(c *gin.Context) {
	var req request.LoginReq
	err := c.ShouldBind(&req)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "数据不能为空",
		})
		return
	}
	res, err := services.GetUserInfo(req.Mobile)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "账号不存在自动创建",
		})
		user := dao.User{
			Mobile: req.Mobile,
		}
		err = services.CreateUser(user)
		return
	}
	val := global.RedisClient.Get(services.GetSmsKey(req.Mobile)).Val()
	if val != req.Codes {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "超过5次则需要重新发送新的验证码",
		})
		return
	}
	customClaims := pkg.CustomClaims{
		ID: res.ID,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: time.Now().Unix() + 86400,
		},
	}
	token, err := pkg.NewJWT("2209A").CreateToken(customClaims)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "登录失败",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "登录成功",
			"data": token,
		})
	}
}

func Register(c *gin.Context) {
	var req request.RegisterReq
	err := c.ShouldBind(&req)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "数据不能为空",
		})
		return
	}
	user := dao.User2{
		Name: req.Name,
		Pass: req.Pass,
	}
	err = services.CreateUser2(user)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "注册失败",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "注册成功",
		})
	}
}

func NameLogin(c *gin.Context) {
	var req request.NameLoginReq
	err := c.ShouldBind(&req)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "数据不能为空",
		})
		return
	}
	rea, err := services.GetUserInfo2(req.Name)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "登录失败",
		})
		return
	}
	customClaims := pkg.CustomClaims{
		ID: rea.ID,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: time.Now().Unix() + 86400,
		},
	}
	token, err := pkg.NewJWT("2209A").CreateToken(customClaims)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "登录失败",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "登录成功",
			"data": token,
		})
	}
}

func Publish(c *gin.Context) {
	var req request.PublishReq
	err := c.ShouldBind(&req)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "数据不能为空",
		})
		return
	}
	user := dao.Update{
		UserId:  req.UserId,
		Title:   req.Title,
		Content: req.Content,
		Images:  req.Images,
		Videos:  req.Videos,
		LCount:  req.LCount,
		CCount:  req.CCount,
	}
	err = services.PublishUpdates(user)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "发布动态失败",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "发布动态成功",
		})
	}
}

func UploadFile(c *gin.Context) {
	file, err := c.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "获取文件失败",
		})
		return
	}
	if file.Size > 20*1024*1024 {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "文件内存过大",
		})
		return
	}
	ext := filepath.Ext(file.Filename)
	if !(ext == ".png" || ext == ".jpg" || ext == ".jpeg" || ext == ".mp4") {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "文件格式错误",
		})
		return
	}
	uploadFile, err := pkg.UploadFile(file, file.Filename)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "文件上传失败",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "文件上传成功",
			"data": uploadFile,
		})
		return
	}
}

func List(c *gin.Context) {
	var req request.ListReq
	err := c.ShouldBind(&req)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "数据不能为空",
		})
		return
	}
	list, err := services.UpdatesList(req.Content, req.Page, req.PageSize)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "列表展示失败",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "列表展示成功",
			"data": list,
		})
	}
}

func Subscribe(c *gin.Context) {
	var req request.SubscribeReq
	err := c.ShouldBind(&req)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "数据不能为空",
		})
		return
	}
	user := dao.Follow{
		UserId:   req.UserId,
		FollowId: req.FollowId,
	}
	err = services.SubscribeFollow(user)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "关注失败",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "关注成功",
		})
	}
}

func LList(c *gin.Context) {
	var req request.LListReq
	err := c.ShouldBind(&req)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "数据不能为空",
		})
		return
	}
	list, err := services.UpdatesLList(req.Content, req.UserId, req.Page, req.PageSize)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "列表展示失败",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "列表展示成功",
			"data": list,
		})
	}
}

func Spot(c *gin.Context) {
	var req request.SpotReq
	err := c.ShouldBind(&req)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "数据不能为空",
		})
		return
	}
	user := dao.Likes{
		UserId: req.UserId,
		LikeId: req.LikeId,
		Types:  req.Types,
	}
	err = services.SpotLikes(user)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "点赞失败",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "点赞成功",
		})
	}
}

func Del(c *gin.Context) {
	var req request.DelReq
	err := c.ShouldBind(&req)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "数据不能为空",
		})
		return
	}
	err = services.Del(req.UserId, req.Types)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "取消点赞失败",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "取消点赞成功",
		})
	}
}

func Leave(c *gin.Context) {
	var req request.LeaveReq
	err := c.ShouldBind(&req)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "数据不能为空",
		})
		return
	}
	user := dao.Comment{
		UserId:    req.UserId,
		CommentId: req.CommentId,
		Types:     req.Types,
		Content:   req.Content,
	}
	err = services.LeaveComment(user)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "评论失败",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "评论成功",
		})
	}
}

func CommentDel(c *gin.Context) {
	var req request.CommentDelReq
	err := c.ShouldBind(&req)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "数据不能为空",
		})
		return
	}
	err = services.CommentDel(req.UserId, req.Types)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "删除评论失败",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "删除评论成功",
		})
	}
}

func PublishDel(c *gin.Context) {
	var req request.PublishDelReq
	err := c.ShouldBind(&req)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "数据不能为空",
		})
		return
	}
	err = services.UpdateDel(req.UserId)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "删除失败",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "删除成功",
		})
	}
}

/**
{
    "cmd": "online"
}

{
    "cmd":"send",
    "data":{
        "to_user_id": 2,
        "message":"hello 2"
    }
}
*/

var OnlineUser = make(map[int]*websocket.Conn)

type WSReq struct {
	Cmd  string      `json:"cmd"`
	Data interface{} `json:"data"`
}

type WSResp struct {
	Code int         `json:"code"`
	Msg  string      `json:"msg"`
	Data interface{} `json:"data"`
}

type SendS struct {
	ToUserId int    `json:"to_user_id"`
	Message  string `json:"message"`
}

type WSSendReq struct {
	Cmd  string `json:"cmd"`
	Data SendS  `json:"data"`
}

func Chat(c *gin.Context) {

	//get middle userId
	userId := c.GetUint("userId")

	// update websocket
	var upgrader = websocket.Upgrader{} // use default options

	conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		log.Print("upgrade:", err)
		c.JSON(http.StatusOK, gin.H{
			"code": -1,
			"msg":  "websocket fail",
			"data": nil,
		})
		return
	}

	defer conn.Close()

	for {
		_, message, err := conn.ReadMessage()
		if err != nil {
			log.Println("read:", err)
			break
		}

		var req WSReq

		err = json.Unmarshal(message, &req)
		if err != nil {

			WSRespErr(conn, 1000, "illegal json")
			continue
		}

		switch req.Cmd {
		case "online":
			go Online(conn, message, int(userId))
		case "send":
			go Send(conn, message)
		default:
			WSRespErr(conn, 10001, "no function")
		}

	}
}

func Send(conn *websocket.Conn, message []byte) {

	var req WSSendReq
	err := json.Unmarshal(message, &req)
	if err != nil {
		WSRespErr(conn, 20001, "Parsing json failed ")
		return
	}

	if OnlineUser[req.Data.ToUserId] == nil {
		WSRespErr(conn, 20003, "not online")
		return
	}

	WSRespSuccess(OnlineUser[req.Data.ToUserId], req.Data.Message)

	WSRespSuccess(conn, "send ok")

}

func Online(conn *websocket.Conn, message []byte, userId int) {

	OnlineUser[userId] = conn
	WSRespSuccess(conn, userId)
}

func WSRespErr(conn *websocket.Conn, code int, msg string) {
	response := WSResp{
		Code: code,
		Msg:  msg,
		Data: nil,
	}

	responseStr, _ := json.Marshal(response)

	err := conn.WriteMessage(websocket.TextMessage, responseStr)
	if err != nil {
		log.Println("write:", err)
	}
}

func WSRespSuccess(conn *websocket.Conn, data interface{}) {
	response := WSResp{
		Code: 0,
		Msg:  "ok",
		Data: data,
	}

	responseStr, _ := json.Marshal(response)

	err := conn.WriteMessage(websocket.TextMessage, responseStr)
	if err != nil {
		log.Println("write:", err)
	}
}

func PullGroup(c *gin.Context) {
	var req request.PullGroupReq
	err := c.ShouldBind(&req)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "数据不能为空",
		})
		return
	}
	user := dao.Group{
		GroupId:  req.GroupId,
		UserId1:  req.UserId1,
		UserId2:  req.UserId2,
		LeaderId: req.LeaderId,
	}
	err = services.CreateGroup(user)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "创建群聊失败",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "创建群聊成功",
		})
	}
}

func DelGroup(c *gin.Context) {
	var req request.DelGroupReq
	err := c.ShouldBind(&req)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "数据不能为空",
		})
		return
	}
	err = services.DelGroup(req.GroupId, req.LeaderId)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "删除群聊失败",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "删除群聊成功",
		})
	}
}

func PullPeople(c *gin.Context) {
	var req request.PullPeopleReq
	err := c.ShouldBind(&req)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "数据不能为空",
		})
		return
	}
	user := dao.Pull{
		GroupId:  req.GroupId,
		PullId:   req.PullId,
		PeopleId: req.PeopleId,
		Types:    req.Types,
	}
	err = services.CreatePull(user)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "拉人失败",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "拉人成功",
		})
	}
}

func AddMember(c *gin.Context) {
	var req request.AddMemberReq
	err := c.ShouldBind(&req)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "数据不能为空",
		})
		return
	}
	user := dao.Member{
		UserId:   req.UserId,
		Position: req.Position,
	}
	err = services.CreateMember(user)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "任命失败",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "任命成功",
		})
	}
}

func DelMember(c *gin.Context) {
	var req request.DelMemberReq
	err := c.ShouldBind(&req)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "数据不能为空",
		})
		return
	}
	err = services.DelMember(req.UserId)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "删除成员失败",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "删除成员成功",
		})
	}
}
